package com.sun.dream.fish.secret.symmetry;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.engines.TwofishEngine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Base64;

import java.nio.charset.StandardCharsets;

public class TwoFishExample {
    private static final String KEY = "0123456789abcdef01234567";

    public static void main(String[] args) throws Exception {
        String plainText = "Hello, World!";
        System.out.println("Original Text: " + plainText);

        String encryptedText = encrypt(plainText);
        System.out.println("Encrypted Text: " + encryptedText);

        String decryptedText = decrypt(encryptedText);
        System.out.println("Decrypted Text: " + decryptedText);
    }

    private static String encrypt(String plainText) throws Exception {
        BlockCipher blowfish = new TwofishEngine();
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blowfish);
        cipher.init(true, new KeyParameter(KEY.getBytes(StandardCharsets.UTF_8)));

        byte[] inputBytes = plainText.getBytes(StandardCharsets.UTF_8);
        byte[] outputBytes = new byte[cipher.getOutputSize(inputBytes.length)];
        int length = cipher.processBytes(inputBytes, 0, inputBytes.length, outputBytes, 0);
        length += cipher.doFinal(outputBytes, length);

        byte[] encodedBytes = Base64.encode(outputBytes, 0, length);
        return new String(encodedBytes, StandardCharsets.UTF_8);
    }

    private static String decrypt(String encryptedText) throws Exception {
        BlockCipher blowfish = new TwofishEngine();
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blowfish);
        cipher.init(false, new KeyParameter(KEY.getBytes(StandardCharsets.UTF_8)));

        byte[] inputBytes = Base64.decode(encryptedText);
        byte[] outputBytes = new byte[cipher.getOutputSize(inputBytes.length)];
        int length = cipher.processBytes(inputBytes, 0, inputBytes.length, outputBytes, 0);
        length += cipher.doFinal(outputBytes, length);

        return new String(outputBytes, 0, length, StandardCharsets.UTF_8);
    }
}